import subprocess
import time
import signal
import sys
import platform

class CameraRTMPStreamer:
    def __init__(self, rtmp_url, camera_index=0):
        self.rtmp_url = rtmp_url
        self.camera_index = camera_index
        self.process = None

        # 注册信号处理，确保程序退出时能正确终止ffmpeg进程
        signal.signal(signal.SIGINT, self.handle_signal)
        signal.signal(signal.SIGTERM, self.handle_signal)

        # 根据操作系统确定摄像头设备路径
        self.camera_path = self._get_camera_path()

    def _get_camera_path(self):
        """根据操作系统获取摄像头设备路径"""
        os_name = platform.system()
        if os_name == "Linux":
            return f"/dev/video{self.camera_index}"
        elif os_name == "Windows":
            return f"video={self.camera_index}"
        elif os_name == "Darwin":  # macOS
            return f"{self.camera_index}"
        else:
            raise Exception(f"不支持的操作系统: {os_name}")

    def handle_signal(self, signum, frame):
        """处理退出信号，确保ffmpeg进程被正确终止"""
        print("\n收到退出信号，正在停止推流...")
        if self.process:
            self.process.terminate()
            time.sleep(1)
            if self.process.poll() is None:
                self.process.kill()
        sys.exit(0)

    def start_streaming(self):
        """开始从摄像头捕获画面并推流"""
        # 根据操作系统构建不同的ffmpeg命令
        os_name = platform.system()

        # 基础推流参数
        base_cmd = [
            'ffmpeg',
            '-f', '',  # 输入格式，将在下面根据系统设置
            '-i', self.camera_path,  # 摄像头设备
            '-c:v', 'libx264',       # 视频编码器
            '-preset', 'ultrafast',  # 编码速度
            '-tune', 'zerolatency',  # 零延迟模式
            '-r', '30',              # 帧率
            '-s', '1280x720',        # 分辨率，可以根据需要调整
            '-pix_fmt', 'yuv420p',   # 像素格式
            '-c:a', 'aac',           # 音频编码器
            '-ar', '44100',          # 音频采样率
            '-b:a', '128k',          # 音频比特率
            '-f', 'flv',             # 输出格式
            self.rtmp_url
        ]

        # 设置输入格式
        if os_name == "Linux":
            base_cmd[2] = 'v4l2'  # Linux使用v4l2框架
        elif os_name == "Windows":
            base_cmd[2] = 'dshow'  # Windows使用directshow
        elif os_name == "Darwin":
            base_cmd[2] = 'avfoundation'  # macOS使用avfoundation

        try:
            print(f"开始从摄像头推流到: {self.rtmp_url}")
            print(f"使用摄像头设备: {self.camera_path}")

            # 启动ffmpeg进程
            self.process = subprocess.Popen(
                base_cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                universal_newlines=True
            )

            # 实时输出ffmpeg的日志
            for line in self.process.stdout:
                print(line.strip())

            # 等待进程结束
            self.process.wait()

            # 检查是否正常结束
            if self.process.returncode == 0:
                print("推流正常结束")
            else:
                print(f"推流异常结束，返回代码: {self.process.returncode}")

        except Exception as e:
            print(f"推流过程中发生错误: {str(e)}")
            if self.process:
                self.process.terminate()

if __name__ == "__main__":
    # 配置推流参数
    rtmp_server = "rtmp://8.155.164.202/live/"
    stream_key = "29c8dda8c28a?secret=5B049044B4914857"
    rtmp_url = f"{rtmp_server}{stream_key}"

    # 摄像头索引，默认0表示第一个摄像头，如有多个摄像头可尝试1,2等
    camera_index = 0

    # 创建推流实例并开始推流
    streamer = CameraRTMPStreamer(rtmp_url, camera_index)
    streamer.start_streaming()